use std::{collections::HashMap, fs};

use serde::{Deserialize, Serialize};
use shq_common::prelude::{
    clickhouse::table_is_exist, get_work_path, DataType, DefaultValue
};
use crate::database::SqlExecutor;
use super::{get_rept_config, Report, ReptType};

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct DataSource {
    pub source_type: DataSourceType,
    #[serde(default)]
    pub ref_repts: Vec<RefReport>,
    pub content: String,
    #[serde(default)]
    pub where_cause: Option<String>,
}
impl DataSource {
    pub(super) async fn parse(
        &self,
        rept_name: &str,
        rept_conf: &Report,
    ) -> anyhow::Result<Vec<(String, DataType)>> {
        // for ref_rept in &self.ref_repts {
        //     if ref_rept.name.is_empty() {
        //         anyhow::bail!("data_source配置错误，ref_rept_names不能为空")
        //     }
        //     let rept = get_rept_config(ref_rept.name.as_str())
        //         .ok_or(anyhow::anyhow!("报表{}不存在", ref_rept.name))?;
        //     for (k,v) in ref_rept.param_map.iter(){
        //         if rept.params.iter().find(|p|&p.name==k).is_none(){
        //             anyhow::bail!("data_source-ref_repts配置错误，引用报表{}的参数{}在param-map中不存在",ref_rept.name,k)
        //         }
        //         if let DefaultValue::Str(sv)=v{
        //             if sv.starts_with("@") {
        //                 let param_name = &sv[1..];
        //                 if rept.params.iter().find(|p|&p.name==param_name).is_none(){
        //                     anyhow::bail!("data_source-ref_repts配置错误，param-map的引用参数{}在报表{}中不存在",param_name,rept_name)
        //                 }
        //             }
        //         }
        //     }
        //     Box::pin(rept.data_source.parse(ref_rept.name.as_str(), rept_conf)).await?;
        // }
        if self.source_type != DataSourceType::Table && self.where_cause.is_some() {
            anyhow::bail!("data_source配置错误，报表数据源类型不是Table,无需where_cause")
        }
        let mut params: Vec<(&str, String)> = Vec::new();
        for p in rept_conf.params.iter() {
            p.parse().await?;
            let dval = p.default_value.get_value().await?;
            params.push((p.name.as_str(), dval));
        }
        let params = params
            .iter()
            .map(|(k, v)| (*k, v.as_str()))
            .collect::<Vec<_>>();
        match self.source_type {
            DataSourceType::Table => {
                if let Some(wc) = self.where_cause.as_ref() {
                    for (k, _v) in params.iter() {
                        if !wc.contains(k) {
                            anyhow::bail!("data_source配置错误，报表数据源类型为Table并且配置了参数，但是where_cause中没有包含参数{}", k)
                        }
                    }
                } else if params.len() > 0 {
                    anyhow::bail!("data_source配置错误，报表数据源类型为Table并且配置了参数，但是where_cause为空")
                }
                let table_name = self.content.as_str();
                let is_exist = table_is_exist(table_name).await?;
                if !is_exist {
                    anyhow::bail!("data_source配置错误，表{}不存在", table_name)
                }
                let sql=if let Some(wc)=&self.where_cause{
                    format!("select * from {} where {}",table_name,wc)
                }else{
                    table_name.to_owned()
                };
                exec_sql(rept_name, rept_conf, &sql, &params).await
            }
            DataSourceType::Sql => {
                exec_sql(rept_name, rept_conf, &self.content, &params).await
            }
            DataSourceType::SqlFile => {
                let file_path = format!("{}/sqls/{}", get_work_path(), self.content);
                let sql = fs::read_to_string(file_path)?;
                let se = SqlExecutor::new(rept_name, &params);
                let leaf_cols = rept_conf.get_leaf_columns();
                se.exec(
                    &sql,
                    &leaf_cols,
                    &rept_conf.params,
                    &rept_conf.groups,
                    &rept_conf.unique_columns,
                )
                .await?;
                se.get_columns().await
            }
            DataSourceType::Func => {
                let se = SqlExecutor::new(rept_name, &params);
                let leaf_cols = rept_conf.get_leaf_columns();
                se.exec_func(&self.content, &leaf_cols, &rept_conf.groups,&rept_conf.unit)
                    .await?;
                se.get_columns().await
            }
        }
    }
}

async fn exec_sql(
    rept_name: &str,
    rept_conf: &Report,
    sql: &str,
    params: &[(&str, &str)],
) -> anyhow::Result<Vec<(String, DataType)>> {
    let se = SqlExecutor::new(rept_name, params);
    if rept_conf.r#type == ReptType::Cross {
        se.exec_cross(
            sql,
            &rept_conf.columns,
            &rept_conf.rows,
            &rept_conf.cells,
            &rept_conf.column_levels,
            &rept_conf.groups,
            &rept_conf.unique_columns,
            &rept_conf.params,
            rept_conf.unit.clone(),
        )
        .await?;
    } else {
        let leaf_cols = rept_conf.get_leaf_columns();
        se.exec(
            sql,
            &leaf_cols,
            &rept_conf.params,
            &rept_conf.groups,
            &rept_conf.unique_columns,
        )
        .await?;
    }
    se.get_columns().await
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub enum DataSourceType {
    Table,
    Sql,
    SqlFile,
    Func,
}

impl<'de> Deserialize<'de> for DataSourceType {
    fn deserialize<D>(deserializer: D) -> std::result::Result<DataSourceType, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        match s.to_lowercase().as_str() {
            "table" => Ok(DataSourceType::Table),
            "sql" => Ok(DataSourceType::Sql),
            "sqlfile" => Ok(DataSourceType::SqlFile),
            "func" => Ok(DataSourceType::Func),
            _ => Err(serde::de::Error::custom(format!(
                "未知的DataSourceType: {}",
                s
            ))),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub enum CacheMode {
    Table,
    Redis,
}

impl Default for CacheMode {
    fn default() -> Self {
        CacheMode::Table
    }
}
impl<'de> Deserialize<'de> for CacheMode {
    fn deserialize<D>(deserializer: D) -> std::result::Result<CacheMode, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        match s.to_lowercase().as_str() {
            "table" => Ok(CacheMode::Table),
            "redis" => Ok(CacheMode::Redis),
            _ => Err(serde::de::Error::custom(format!(
                "未知的CacheMode: {}",
                s
            ))),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RefReport {
    pub name: String,
    pub param_map: HashMap<String, DefaultValue>,
}
